package com.mojo.concurrent.concurrent_05_util;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 循环栅栏工具类示例
 * <p>
 * 场景：N个子线程执行到一定程度，需要等待；阻塞N个线程后被唤醒再继续执行
 * </p>
 *
 * @author <a href="mailto:sjj@jianzhimao.com">mojo</a>
 * copyright (C), 2013-2021, 广州九尾信息科技有限公司
 * @date 2021/8/20 14:33
 */
public class CyclicBarrierDemo1 {
    public static void main(String[] args) {
        CyclicBarrierTask();
        //priorityBarrierAction();
    }

    private static void CyclicBarrierTask() {
        //设置barrier阻塞个数
        CyclicBarrier barrier = new CyclicBarrier(10, new Thread() {
            @Override
            public void run() {
                //barrier action,
                System.out.println(Thread.currentThread().getName() + "最后到达，执行barrier action");
            }
        });
        //创建线程
        for (int i = 0; i < 10; i++) {
            new Thread(new CyclicBarrierTask(barrier), "barrier线程-Thread--" + i).start();
        }
        //线程等待
        //try {
        //    barrier.await();
        //} catch (InterruptedException | BrokenBarrierException e) {
        //    throw new RuntimeException(e);
        //}
        System.out.println("主线程===>" + Thread.currentThread().getName());
        //barrier.reset();
        //for (int i = 0; i < 5; i++) {
        //    new Thread(new CyclicBarrierTask(barrier), "第二轮，barrier线程-Thread--" + i).start();
        //}
        //System.out.println("主线程2===>" + Thread.currentThread().getName());
    }

    // CyclicBarrier实现线程优先级
    private static void priorityBarrierAction() {
        int parties = 2;
        Runnable r = () -> {
            try {
                Thread.sleep(200L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("最先执行线程1");
        };
        CyclicBarrier cb = new CyclicBarrier(parties, r);
        Thread thread = new Thread(() -> {
            try {
                for (int i = 0; i < parties; i++) {
                    try {
                        cb.await(2, TimeUnit.SECONDS);
                    } catch (TimeoutException e) {
                        throw new RuntimeException(e);
                    }
                }
                System.out.println("非优先线程>>");
            } catch (InterruptedException | BrokenBarrierException e) {
                throw new RuntimeException(e);
            }
        });
        thread.start();
        try {
            cb.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            throw new RuntimeException(e);
        }
    }

    static class CyclicBarrierTask implements Runnable {
        CyclicBarrier barrier;

        public CyclicBarrierTask(CyclicBarrier barrier) {
            this.barrier = barrier;
        }

        @Override
        public void run() {
            //执行业务
            int millis = new Random().nextInt(5000);
            try {
                // 打乱线程执行顺序
                System.out.println(Thread.currentThread().getName() + " await");
                // 线程到达栅栏，等待count==0时的线程到达，执行barrier action,然后所有线程继续执行
                TimeUnit.MILLISECONDS.sleep(millis);
                barrier.await();
                System.out.println(Thread.currentThread().getName() + ",休眠时间" + millis + "继续执行。。。");
                //线程阻塞,可重用
                TimeUnit.MILLISECONDS.sleep(millis);
                barrier.await();
                System.out.println(Thread.currentThread().getName() + ",再次休眠时间" + millis + "继续执行。。。");
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
